package com.example.photo.filter;

import com.example.photo.common.ErrorCode;
import com.example.photo.exception.BusinessException;
import com.example.photo.utils.JwtTokenUtils;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

/**
 * 全局Token校验过滤器
 *
 * @author Lwh
 * @time 2023/03/26 12:54
 */
public class TokenFilter implements Filter {

    // 排除的路径
    private String[] excludedURIs;

    @Override
    public void init(FilterConfig filterConfig) {
        String param = filterConfig.getInitParameter("excludedURIs");
        if (StringUtils.isNotBlank(param)) {
            this.excludedURIs = param.split(",");
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;

        // 判断是否是被排除的路径
        boolean flag = false;
        for (String uri : excludedURIs) {
            if (req.getRequestURI().equals(uri)) {
                flag = true;
                break;
            }
        }

        if (flag) {
            chain.doFilter(request, response);
        }

        // 需要token，获取
        String token = req.getHeader(JwtTokenUtils.TOKEN_HEADER);

        if (StringUtils.isNotBlank(token) && isValidToken(token)) {
            // 将用户身份信息放入请求头中
            String id = String.valueOf(JwtTokenUtils.getUserIdFromToken(token));
            String role = String.valueOf(JwtTokenUtils.getUserRoleFromToken(token));
            HeaderMapRequestWrapper headerMapRequestWrapper = new HeaderMapRequestWrapper(req);
            if (!StringUtils.isAnyBlank(id, role)) {
                headerMapRequestWrapper.addHeader(JwtTokenUtils.ROLE_HEADER, role);
                headerMapRequestWrapper.addHeader(JwtTokenUtils.USERID_HEADER, id);
            } else {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "无法正确解析token");
            }
            chain.doFilter(headerMapRequestWrapper, response);
        } else {
            // token为空或校验失败，401
            HttpServletResponse resp = (HttpServletResponse) response;
            resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        }
    }

    private boolean isValidToken(String token) {
        return !JwtTokenUtils.isTokenExpired(token);
    }
}

/**
 * 装饰器，修改请求头
 */
class HeaderMapRequestWrapper extends HttpServletRequestWrapper {
    public HeaderMapRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    private final Map<String, String> headerMap = new HashMap<>();

    public void addHeader(String name, String value) {
        headerMap.put(name, value);
    }

    @Override
    public String getHeader(String name) {
        String headerValue = super.getHeader(name);
        if (headerMap.containsKey(name)) {
            headerValue = headerMap.get(name);
        }
        return headerValue;
    }

    @Override
    public Enumeration<String> getHeaderNames() {
        List<String> names = Collections.list(super.getHeaderNames());
        names.addAll(headerMap.keySet());
        return Collections.enumeration(names);
    }

    @Override
    public Enumeration<String> getHeaders(String name) {
        List<String> values = Collections.list(super.getHeaders(name));
        if (headerMap.containsKey(name)) {
            values = Collections.singletonList(headerMap.get(name));
        }
        return Collections.enumeration(values);
    }
}

